﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DynORM.Interfaces;
using DynORM.Mappers;
using DynORM.Enums;
using DynORM;
using DynORM.ValueObjects;
using DynORM.ReferenceObjects;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using System.Globalization;

namespace UnitTests.DAL
{
    [TestClass]
    public class FieldSerializationUnitTests
    {
        private IField GenerateNewField(Type type, string name, object value)
        {
            return new Field(type, name, value);
        }

        private string XmlXPathRunner(string xml, string xpath)
        {
            //intencially use XPath here in order to make this test independed from formatters
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);

            //XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
            //nsmgr.AddNamespace("ns", "http://schemas.datacontract.org/2004/07/IEOServerJobWebAPI.Auxiliary");
            //nsmgr.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");

            //XmlNode node = doc.SelectSingleNode(xpath, nsmgr);
            XmlNode node = doc.SelectSingleNode(xpath);

            return node.InnerText;
        }

        [TestMethod]
        public void SerializeFieldTest()
        {
            string xml;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(string), "TestColumn", "12345678");
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual("12345678", res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.String"">12345678</Field>");
        }

        [TestMethod]
        public void DeserializeFieldTest()
        {
            IField f;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(string), "TestColumn", "12345678");
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(string));

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeIntFieldTest()
        {
            string xml;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(int), "TestColumn", 12345);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual("12345", res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.Int32"">12345</Field>");
        }

        [TestMethod]
        public void DeserializeIntFieldTest()
        {
            IField f;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(int), "TestColumn", 12345);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(int));
            Assert.AreEqual<int>((int)f.FieldValue, 12345);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeInt16FieldTest()
        {
            string xml;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(Int16), "TestColumn", 12345);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual("12345", res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.Int16"">12345</Field>");
        }

        [TestMethod]
        public void DeserializeInt16FieldTest()
        {
            IField f;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(Int16), "TestColumn", 12345);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(Int16));
            Assert.AreEqual<Int16>((Int16)f.FieldValue, 12345);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeGuidFieldTest()
        {
            string xml;
            Guid id = Guid.NewGuid();
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(Guid), "TestColumn", id);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual(id.ToString(), res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.Guid"">" + id.ToString() + "</Field>");
        }

        [TestMethod]
        public void DeserializeGuidFieldTest()
        {
            IField f;
            Guid id = Guid.NewGuid();
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(Guid), "TestColumn", id);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(Guid));
            Assert.AreEqual<Guid>((Guid)f.FieldValue, id);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeDecimalFieldTest()
        {
            string xml;
            Decimal num = 123.3m;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(Decimal), "TestColumn", num);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual(((Decimal)num).ToString(CultureInfo.CreateSpecificCulture("en-GB")), res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.Decimal"">" + num.ToString() + "</Field>");
        }

        [TestMethod]
        public void DeserializeDecimalFieldTest()
        {
            IField f;
            Decimal num = 123.5m;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(Decimal), "TestColumn", num);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(Decimal));
            Assert.AreEqual<Decimal>((Decimal)f.FieldValue, num);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeDateTimeFieldTest()
        {
            string xml;
            DateTime dt = DateTime.MinValue;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(DateTime), "TestColumn", dt);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual(((DateTime)dt).ToString(CultureInfo.CreateSpecificCulture("en-GB")), res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.DateTime"">" + dt.ToString() + "</Field>");
        }

        [TestMethod]
        public void DeserializeDateTimeFieldTest()
        {
            IField f;
            DateTime dt = DateTime.MinValue;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(DateTime), "TestColumn", dt);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(DateTime));
            Assert.AreEqual<DateTime>((DateTime)f.FieldValue, dt);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeSingleFieldTest()
        {
            string xml;
            Single s = 123.45f;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(float), "TestColumn", s);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            //Assert.AreEqual(s.ToString(CultureInfo.CreateSpecificCulture("en-GB")), res);
            Assert.AreEqual(((Single)s).ToString(CultureInfo.CreateSpecificCulture("en-GB")), res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.Single"">123,45</Field>");
        }

        [TestMethod]
        public void DeserializeSingleFieldTest()
        {
            IField f;
            Single s = 123.45f;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(float), "TestColumn", s);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(float));
            Assert.AreEqual<float>((float)f.FieldValue, 123.45f);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeDoubleFieldTest()
        {
            string xml;
            Double d = 123.45d;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(double), "TestColumn", d);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual(((Double)d).ToString(CultureInfo.CreateSpecificCulture("en-GB")), res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.Double"">123,45</Field>");
        }

        [TestMethod]
        public void DeserializeDoubleFieldTest()
        {
            IField f;
            Double d = 123.45d;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(double), "TestColumn", d);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(double));
            Assert.AreEqual<double>((double)f.FieldValue, 123.45d);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeNullableIntFieldTest()
        {
            string xml;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(int?), "TestColumn", 12345);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual("12345", res);
            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"">12345</Field>");
        }

        [TestMethod]
        public void DeserializeNullableIntFieldTest()
        {
            IField f;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(int?), "TestColumn", 12345);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(int?));
            Assert.AreEqual<int?>((int?)f.FieldValue, 12345);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


        [TestMethod]
        public void SerializeNullableDateTimeFieldTest()
        {
            string xml;
            DateTime? dt = DateTime.MinValue;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                IField f = GenerateNewField(typeof(DateTime?), "TestColumn", dt);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            string res = XmlXPathRunner(xml, "//Field[1]/@FieldName");
            Assert.AreEqual("TestColumn", res);
            res = XmlXPathRunner(xml, "//Field[1]");
            Assert.AreEqual(dt.ToString(), res);

            //Assert.AreEqual(xml, @"<?xml version=""1.0"" encoding=""windows-1251""?><Field FieldName=""TestColumn"" FieldType=""System.Nullable`1[[System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"">" + dt.ToString() + "</Field>");
        }

        [TestMethod]
        public void DeserializeNullableDateTimeFieldTest()
        {
            IField f;
            DateTime? dt = DateTime.MinValue;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlTextWriter writer = new XmlTextWriter(ms, UTF8Encoding.Default);

                XmlSerializer formatter = new XmlSerializer(typeof(Field));
                f = GenerateNewField(typeof(DateTime?), "TestColumn", dt);
                formatter.Serialize(writer, f);

                ms.Position = 0;
                XmlTextReader reader = new XmlTextReader(ms);
                f = (IField)formatter.Deserialize(reader);
            }

            Assert.AreEqual(f.FieldName, "TestColumn");
            Assert.AreEqual<Type>(f.FieldType, typeof(DateTime?));
            Assert.AreEqual<DateTime?>((DateTime?)f.FieldValue, dt);

            ((IORMObject)f).CheckValuesIntegrity(false);
        }


    }
}
